package Client;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import org.apache.commons.io.IOUtils;

public class Client extends JFrame implements ActionListener {

    private JButton send, attach, exit, login, logout;
    private JPanel p_login, p_chat;
    private JTextField nick, nick1, message;
    private JTextArea msg, online;
    private Socket client;
    private Socket fileSocket;
    private ServerSocket fileServer;
    private DataStream dataStream;
    private DataOutputStream dos;
    private DataInputStream dis;
    private boolean isSuccess = false;

    public Client() {
        super("Chat: Client");
        setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        this.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                exit();
            }
        });
        setSize(600, 400);
        addItem();
        setVisible(true);
    }

    private void addItem() {
        setLayout(new BorderLayout());

        exit = new JButton("Thoat");
        exit.addActionListener(this);
        send = new JButton("Gui");
        send.addActionListener(this);
        attach = new JButton("File dinh kem");
        attach.addActionListener(this);
        login = new JButton("Dang nhap");
        login.addActionListener(this);
        logout = new JButton("Thoat");
        logout.addActionListener(this);

        p_chat = new JPanel();
        p_chat.setLayout(new BorderLayout());

        JPanel p1 = new JPanel();
        p1.setLayout(new FlowLayout(FlowLayout.LEFT));
        nick = new JTextField(20);
        p1.add(new JLabel("Nick: "));
        p1.add(nick);
        p1.add(exit);

        JPanel p2 = new JPanel();
        p2.setLayout(new BorderLayout());

        JPanel p22 = new JPanel();
        p22.setLayout(new FlowLayout(FlowLayout.CENTER));
        p22.add(new JLabel("Danh sach online"));
        p2.add(p22, BorderLayout.NORTH);

        online = new JTextArea(10, 10);
        online.setEditable(false);
        p2.add(new JScrollPane(online), BorderLayout.CENTER);
        p2.add(new JLabel("     "), BorderLayout.SOUTH);
        p2.add(new JLabel("     "), BorderLayout.EAST);
        p2.add(new JLabel("     "), BorderLayout.WEST);

        msg = new JTextArea(10, 20);
        msg.setEditable(false);

        JPanel p3 = new JPanel();
        p3.setLayout(new FlowLayout(FlowLayout.LEFT));
        p3.add(new JLabel("Tin nhan"));
        message = new JTextField(30);
        message.addActionListener(this);
        message.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {

                if (e.getKeyCode() == KeyEvent.VK_ENTER) {
                    checkSend(message.getText() + "\n");
                    message.setText("");
                    message.requestFocus();
                }
            }
        });
        p3.add(message);
        p3.add(send);
        p3.add(attach);

        p_chat.add(new JScrollPane(msg), BorderLayout.CENTER);
        p_chat.add(p1, BorderLayout.NORTH);
        p_chat.add(p2, BorderLayout.EAST);
        p_chat.add(p3, BorderLayout.SOUTH);
        p_chat.add(new JLabel("     "), BorderLayout.WEST);

        p_chat.setVisible(false);
        add(p_chat, BorderLayout.CENTER);
        //-------------------------
        p_login = new JPanel();
        p_login.setLayout(new FlowLayout(FlowLayout.CENTER));
        p_login.add(new JLabel("Nick: "));
        nick1 = new JTextField(20);
        p_login.add(nick1);
        p_login.add(login);
        p_login.add(logout);

        add(p_login, BorderLayout.NORTH);
    }
//---------[ Socket ]-----------//	

    private void go() {
        try {
            client = new Socket("localhost", 1391);
            dos = new DataOutputStream(client.getOutputStream());
            dis = new DataInputStream(client.getInputStream());
            //client.close();
        } catch (Exception e) {
            JOptionPane.showMessageDialog(this, "Loi ket noi.", "Message Dialog", JOptionPane.WARNING_MESSAGE);
            System.exit(0);
        }
    }

    public static void main(String[] args) {
        new Client().go();
    }

    private void sendMSG(String data) {
        try {
            dos.writeUTF(data);
            dos.flush();
        } catch (IOException e) {
        }
    }

    private String getMSG() {
        String data = null;
        try {
            data = dis.readUTF();
        } catch (IOException e) {
        }
        return data;
    }

    public void getMSG(String msg1, String msg2) {
        int stt = Integer.parseInt(msg1);
        switch (stt) {
            case 3:             // nhan tin nhan tu nguoi khac
                this.msg.append(msg2);
                break;
            case 4:             // update danh sach online
                this.online.setText(msg2);
                break;
            case 5:             // nhan file
                try {
                    int port = Integer.parseInt(msg2.substring(msg2.length() - 4));
                    String fileName = msg2.substring(0, msg2.length() -4);
                    fileSocket = new Socket("localhost", port);
                    String filePath = saveFile(fileName);
                    receiveFile(fileSocket, filePath);
                    this.msg.append(fileName + "\n");
                } catch (NumberFormatException | IOException e) {
                }
                break;
            case 6:             // thoat server
                dataStream.stopThread();
                exit();
                break;
            default:
                break;
        }
    }
//----------------------------------------------

    private void checkSend(String msg) {
        if (msg.compareTo("\n") != 0) {
            this.msg.append("Toi : " + msg);
            sendMSG("1");
            sendMSG(msg);
        }
    }

    private boolean checkLogin(String nick) {
        if (nick.compareTo("") == 0) {
            return false;
        } else if (nick.compareTo("0") == 0) {
            return false;
        } else {
            sendMSG(nick);
            int sst = Integer.parseInt(getMSG());
            if (sst == 0) {
                return false;
            } else {
                return true;
            }
        }
    }

    private void exit() {
        try {
            sendMSG("0");
            dos.close();
            dis.close();
            client.close();
        } catch (IOException e1) {
        }
        System.exit(0);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == exit) {
            dataStream.stopThread();
            exit();
        } else if (e.getSource() == attach) {
            String filePath = openFile();
            final File file = new File(filePath);
//            System.out.println("File path: " + filePath);
            try {
                int port = 1234;
                boolean isOpen = false;
                while (!isOpen) {
                    try {
                        fileServer = new ServerSocket(port);
                        isOpen = true;
                        fileServer.setReuseAddress(true);
                    } catch (Exception ex) {
                        port++;
                        isOpen = false;
                    }
                }
//                System.out.println("Socket: " + fileServer.toString());
                sendMSG("2");
                String msg = file.getName() + port;
                sendMSG(msg);

                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        while (true) {
                            try {
                                fileSocket = fileServer.accept();
                                if (fileSocket != null) {
                                    sendFile(fileSocket, file);
                                    if (isSuccess) {
                                        isSuccess = false;
                                        break;
                                    }
                                }
                            } catch (Exception e) {
                            }
                        }
                    }
                }).start();
                
            } catch (Exception ex) {
            }
        } else if (e.getSource() == send) {
            checkSend(message.getText() + "\n");
            message.setText("");
            message.requestFocus();
        } else if (e.getSource() == login) {
            if (checkLogin(nick1.getText())) {
                p_chat.setVisible(true);
                p_login.setVisible(false);
                nick.setText(nick1.getText());
                nick.setEditable(false);
                this.setTitle(nick1.getText());
                msg.append("Dang nhap thanh cong\n");
                dataStream = new DataStream(this, this.dis);
            } else {
                JOptionPane.showMessageDialog(this, "Nick da ton tai, nhap lai.", "Message Dialog", JOptionPane.WARNING_MESSAGE);
                nick1.requestFocus();
            }
        } else if (e.getSource() == logout) {
            exit();
        }
    }

    private String saveFile(String filePath) {
        JFileChooser jFile = new JFileChooser();
        String nameOfFile = filePath.substring(filePath.lastIndexOf(":") + 2);
        File file = null;
        jFile.setSelectedFile(new File(nameOfFile));
        int returnVal = jFile.showSaveDialog(Client.this);
        if (returnVal == JFileChooser.APPROVE_OPTION) {
            file = jFile.getSelectedFile();
        }
        return file.getAbsolutePath();
    }

    private String openFile() {
        File file = null;
        JFileChooser jFile = new JFileChooser();
        int returnVal = jFile.showOpenDialog(Client.this);
        if (returnVal == JFileChooser.APPROVE_OPTION) {
            file = jFile.getSelectedFile();
        }
        return file.getAbsolutePath();
    }

    private void receiveFile(final Socket socket, final String path) {

        new Thread(new Runnable() {
            @Override
            public void run() {
                File file = new File(path);
                DataInputStream is = null;
                DataOutputStream os = null;
                try {
                    is = new DataInputStream(socket.getInputStream());
                    os = new DataOutputStream(new FileOutputStream(file));
                    System.out.println("Receiving file: " + file.getName());
                    System.out.println("Received " + IOUtils.copy(is, os) + " bytes");
                    os.flush();
                } catch (Exception e) {
                } finally {
                    try {
//                        System.out.println("Socket: " + fileSocket.toString());
                        is.close();
                        os.close();
//                        Thread.sleep(500);
                        fileSocket.close();
//                        System.out.println("Socket (closed): " + fileSocket.toString());
                    } catch (Exception e) {
                    }
                }
            }
        }).start();
    }

    private void sendFile(final Socket socket, final File file) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                DataOutputStream os = null;
                DataInputStream is = null;
                try {
                    os = new DataOutputStream(socket.getOutputStream());
                    is = new DataInputStream(new FileInputStream(file));
                    System.out.println("Sending file " + file.getName());
                    System.out.println("Sent " + IOUtils.copy(is, os) + " bytes");
                    os.flush();
                    msg.append("Sent file: " + file.getName() + "\n");
                    isSuccess = true;
                } catch (Exception ex) {
                } finally {
                    try {
//                        System.out.println("Socket: " + fileSocket.toString());
                        is.close();
                        os.close();
//                        Thread.sleep(500);
                        fileSocket.close();
//                        System.out.println("Socket (closed): " + fileSocket.toString());
                    } catch (Exception e) {
                    }
                }
            }
        }).start();
    }

    private void receiveFile2(String path) {
        File file = new File(path);
        try {
            OutputStream os = new FileOutputStream(file);
            byte[] buff = new byte[1024];
            int count = 0;
            System.out.println("Receiving file");
            while ((count = dis.read(buff)) != -1) {
                os.write(buff, 0, count);
            }
            System.out.println("Received " + count + " bytes");
            dis.close();
            os.close();
        } catch (Exception e) {
        }
    }

    private void sendFile2(File file) {
        try {
            InputStream is = new FileInputStream(file);
            byte[] buff = new byte[1024];
            int count = 0;
            System.out.println("Sending file");
            while ((count = is.read(buff)) != -1) {
                dos.write(buff, 0, count);
            }
            System.out.println("Sent " + count + " bytes");
            is.close();
            dos.close();
        } catch (Exception e) {
        }
    }
}
